/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 */

package java.nio.channels.spi;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.nio.channels.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.nio.ch.Interruptible;


/**
 * 可中断通道的基本实现类。
 *
 * <p> 这个类封装了实现通道的异步关闭和中断所需的底层机制。
 * 具体的通道类必须分别在调用可能阻塞的I/O操作之前和之后调用begin和end方法。
 * 为了确保end方法总是被调用，这些方法应该在try中使用。finally块:
 *
 * <blockquote><pre>
 * boolean completed = false;
 * try {
 *     begin();
 *     completed = ...;    // Perform blocking I/O operation
 *     return ...;         // Return result
 * } finally {
 *     end(completed);
 * }</pre></blockquote>
 *
 * <p> end方法的已完成参数说明I/O操作是否实际完成，也就是说，它是否对调用程序有任何可见的效果。
 * 例如，在一个读取字节的操作的情况下，这个参数应该是真的，
 * 如果，并且仅当，一些字节实际上被转移到调用者的目标缓冲区。
 *
 * <p> 具体的channel类还必须实现implCloseChannel方法，
 * 如果它被调用，而另一个线程在本地I/O操作中被阻塞，那么该操作将立即返回，要么抛出异常，要么正常返回。
 * 如果线程被中断，或者阻塞线程的通道被异步关闭，那么通道的end方法将抛出相应的异常。
 *
 * <p>这个类执行实现Channel所需的同步规范。
 * implCloseChannel方法的实现不需要与可能试图关闭通道的其他线程同步。</p>
 *
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public abstract class AbstractInterruptibleChannel
    implements Channel, InterruptibleChannel
{

    private final Object closeLock = new Object();
    private volatile boolean open = true;

    /**
     * 初始化此类的新实例
     */
    protected AbstractInterruptibleChannel() { }

    /**
     * 关闭这个通道。
     *
     * <p> 如果通道已经关闭，则此方法立即返回。
     *  否则，它将通道标记为closed，然后调用implCloseChannel方法来完成close操作。</p>
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    public final void close() throws IOException {
        synchronized (closeLock) {
            if (!open)
                return;
            open = false;
            implCloseChannel();
        }
    }

    /**
     * 关闭这个通道。
     *
     * <p> 该方法由close方法调用，以执行关闭通道的实际工作。
     * 只有在通道尚未关闭的情况下才会调用此方法，并且只调用一次。
     *
     * <p> 此方法的实现必须安排，在此通道上的I/O操作中阻塞的任何其他线程，将立即返回，
     * 可以通过抛出异常，也可以通过正常返回。
     * </p>
     *
     * @throws  IOException
     *          If an I/O error occurs while closing the channel
     */
    protected abstract void implCloseChannel() throws IOException;

    public final boolean isOpen() {
        return open;
    }


    // -- Interruption 机制 --

    private Interruptible interruptor;
    private volatile Thread interrupted;

    /**
     * 标记可能无限期阻塞的I/O操作的开始。
     *
     * <p> 该方法应该与end方法一起调用，使用try…finally，
     * 阻塞如上所示，以实现该通道的异步丢失和中断。</p>
     */
    
    /**
     * 标记可能无限期阻塞的I/O操作的开始。
     *
     * <p> 该方法应该与end方法一起调用，使用try…finally，
     * 阻塞如上所示，以实现该通道的异步丢失和中断。</p>
     * 
     * 这里首先建了一个 interruptor 实例, 通过 blockedOn()方法将之设置到
     * 当前线程的Thread的 Interruptible 引用上 . 当当前线程的 interrupt 方法
     * 执行时, 会执行Interruptible#interrupt(). 这时就会自动在中断时执行通道
     * 的关闭方法.
     */
    protected final void begin() {
        if (interruptor == null) {
        	// interruptor 单例模式，设置一个interruptor
            interruptor = new Interruptible() {
            		// target是导致其他线程interrupt的线程
                    public void interrupt(Thread target) {
                        synchronized (closeLock) {
                            if (!open)
                                return;
                            // 对通道执行关闭操作，设置interrupted
                            open = false;
                            interrupted = target;
                            try {
                                AbstractInterruptibleChannel.this.implCloseChannel();
                            } catch (IOException x) { }
                        }
                    }};
        }
        // 会在interruptor上阻塞
        blockedOn(interruptor);
        Thread me = Thread.currentThread();
        // 如果当前线程已经是Interrupted,调用interruptor.interrupt(me)
        if (me.isInterrupted())
            interruptor.interrupt(me);
    }

    /**
     * 标记可能无限期阻塞的I/O操作的结束。
     * 
     * completed 表示操作是否成功完成.
     *
     * <p> 该方法应该与begin方法一起调用，使用try…finally，如上所示的区块，以实现该通道的异步丢失和中断。
     *
     * @param  completed
     *         <tt>true</tt> if, and only if, the I/O operation completed
     *         successfully, that is, had some effect that would be visible to
     *         the operation's invoker
     *
     * @throws  AsynchronousCloseException
     *          If the channel was asynchronously closed
     *
     * @throws  ClosedByInterruptException
     *          If the thread blocked in the I/O operation was interrupted
     */
    protected final void end(boolean completed)
        throws AsynchronousCloseException
    {
    	// 清空阻塞的东西（原来是interruptor）
        blockedOn(null);
        Thread interrupted = this.interrupted;
        // 如果interrupted不为null，而且是线程自己，清空interrupted，抛出ClosedByInterruptException
        if (interrupted != null && interrupted == Thread.currentThread()) {
            interrupted = null;
            throw new ClosedByInterruptException();
        }
        // 如果IO操作未完成，并且通道已关闭，抛出AsynchronousCloseException
        if (!completed && !open)
            throw new AsynchronousCloseException();
    }


    // -- sun.misc.SharedSecrets --
    static void blockedOn(Interruptible intr) {         // package-private
        sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(),
                                                             intr);
    }
}
